﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Animation;
using System.Windows.Shapes;


namespace Silverlight.ControlToolkit.Windows
{

    /// <summary>
    /// 
    /// </summary>
    public partial class ModalDialog : UserControl
    {
        public static readonly DependencyProperty ActionResult = DependencyProperty.RegisterAttached("ActionResult", typeof(DialogResult), typeof(ModalDialog), new PropertyMetadata(new PropertyChangedCallback(OnActionResultChanged)));

        public ModalDialog()
        {
            InitializeComponent();
        }

        private static void OnActionResultChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
        {

            //Remove the event handler if exists
            if ((DialogResult)e.OldValue != DialogResult.None && target is ButtonBase)
            {
                ((ButtonBase)target).Click -= new RoutedEventHandler(ModalDialog_Click);
            }

            if ((DialogResult)e.NewValue != DialogResult.None)
            {
                if (target is ButtonBase)
                {
                    ((ButtonBase)target).Click += new RoutedEventHandler(ModalDialog_Click);
                }
            }
        }

        public static DialogResult GetActionResult(DependencyObject target)
        {
            return (DialogResult)target.GetValue(ActionResult);
        }

        public static void SetActionResult(DependencyObject target, DialogResult value)
        {
            target.SetValue(ActionResult, value);

        }

        //private static readonly DependencyProperty TitleBar = DependencyProperty.RegisterAttached("TitleBar", typeof(UIElement), typeof(ModalDialog), new PropertyMetadata(new PropertyChangedCallback(OnActionResultChanged)));

        //private static void OnTitleBarChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
        //{
            
        //    //Remove the event handler if exists
        //    if ((DialogResult)e.OldValue != DialogResult.None && target is ButtonBase)
        //    {
        //        ((ButtonBase)target).Click -= new RoutedEventHandler(ModalDialog_Click);
        //    }

        //    if ((DialogResult)e.NewValue != DialogResult.None)
        //    {
        //        if (target is ButtonBase)
        //        {
        //            ((ButtonBase)target).Click += new RoutedEventHandler(ModalDialog_Click);
        //        }
        //    }
        //}

        static void ModalDialog_Click(object sender, RoutedEventArgs e)
        {
            if (e.OriginalSource is FrameworkElement)
            {
                ModalDialog objCurrentInstance = GetCurrentModalDialogInstance((FrameworkElement)e.OriginalSource);

                if (objCurrentInstance != null && objCurrentInstance.Visibility == Visibility.Visible)
                    objCurrentInstance.Close((DialogResult)((ButtonBase)e.OriginalSource).GetValue(ActionResult));
            }

            //if (this.Visibility == Visibility.Visible)
            //     this.Close((DialogResult)((ButtonBase)e.Source).GetValue(ActionResult));
        }

        private static ModalDialog GetCurrentModalDialogInstance(FrameworkElement childElement)
        {

            if (VisualTreeHelper.GetParent(childElement) is ModalDialog)
                return (ModalDialog)VisualTreeHelper.GetParent(childElement);
            else if (VisualTreeHelper.GetParent(childElement) is FrameworkElement)
                return GetCurrentModalDialogInstance((FrameworkElement)VisualTreeHelper.GetParent(childElement));
            else
                return null;
        }


        public event DialogBoxClosedEventHandler DialogBoxClosed;
        public event DialogBoxClosingEventHandler DialogBoxClosing;

        public FrameworkElement Owner;
        public FrameworkElement Child;
        private FrameworkElement _originalOwner; 
        private Popup _popup;
        private ModalDialogDragDrop _dragDropInstance;

        /// <summary>
        /// Shows the specified child.
        /// </summary>
        /// <param name="child">The child.</param>
        /// <returns></returns>
        public static ModalDialog Show(FrameworkElement child)
        {
            return Show(null, child, null, null);
        }

        /// <summary>
        /// Shows the specified child in the specified owner.
        /// </summary>
        /// <param name="owner">The owner.</param>
        /// <param name="child">The child.</param>
        /// <returns></returns>
        public static ModalDialog Show(FrameworkElement owner, FrameworkElement child)
        {
            return Show(owner, child, null, null);
        }

        public static ModalDialog Show(FrameworkElement child, Control controlToFocusOn)
        {
            return Show(null, child, controlToFocusOn, null);
        }

        public static ModalDialog Show(FrameworkElement owner, FrameworkElement child, Control controlToFocusOn)
        {
            return Show(owner, child, controlToFocusOn, null);
        }

        /// <summary>
        /// Shows the specified child in the specified owner.
        /// </summary>
        /// <param name="owner">The owner.</param>
        /// <param name="child">The child.</param>
        /// <returns></returns>
        public static ModalDialog Show(FrameworkElement owner, FrameworkElement child, Control controlToFocusOn, UIElement titleBar)
        {

            ModalDialog objModalDialog = new ModalDialog();
            objModalDialog._popup = new System.Windows.Controls.Primitives.Popup();
            //Utilities.GetRootPanel().Children.Add(objModalDialog._popup);
            objModalDialog._popup.Child = objModalDialog;

            FrameworkElement objRoot = Application.Current.RootVisual as FrameworkElement;
            if (owner == null)
            {

                if (objRoot != null)
                {
                    objModalDialog.Width = objRoot.ActualWidth;
                    objModalDialog.Height = objRoot.ActualHeight;
                }
                objModalDialog.Owner = objRoot;
            }
            else
            {
                if (owner is WindowPanel && ((WindowPanel)owner)._contentHolderElement != null) //Change owner to actual body which might be dragged & dropped
                {
                    objModalDialog._originalOwner = owner;
                    objModalDialog.Owner = ((WindowPanel)owner)._contentHolderElement;
                    ((WindowPanel)owner).Dragged += new RoutedEventHandler(objModalDialog.ModalDialog_Dragged);
                    ((WindowPanel)owner).DialogBoxClosing += new DialogBoxClosingEventHandler(objModalDialog.ModalDialog_DialogBoxClosing);
                    ((WindowPanel)owner).DialogBoxClosed += new DialogBoxClosedEventHandler(objModalDialog.ModalDialog_DialogBoxClosed);
                }
                else
                    objModalDialog.Owner = owner;

                objModalDialog.Width = objModalDialog.Owner.ActualWidth;
                objModalDialog.Height = objModalDialog.Owner.ActualHeight;
            }


            //Utilities.GetPanelFromParents(objModalDialog.Owner).Children.Add(objModalDialog._popup);
            objModalDialog._popup.IsOpen = true;
            objModalDialog.Child = child;

            //We added the ChildContainer grid so that the element is positioned in the center of its owner
            objModalDialog.ChildContainer.Children.Add(child);
            //child.SetValue(Grid.RowProperty, 1);
            //child.SetValue(Grid.ColumnProperty, 1);

            //if (objModalDialog.Owner != objRoot)
            //    objModalDialog._popup.PlaceInCenter(objModalDialog.Owner);

            if (objModalDialog.Owner != null)
                objModalDialog._popup.PlaceInsideOwner(objModalDialog.Owner);

            objModalDialog.Loaded += new RoutedEventHandler(objModalDialog.objModalDialog_Loaded);

            WindowPanel objChildWindow = ((FrameworkElement)objModalDialog.ChildContainer).GetChildByType(typeof(WindowPanel)) as WindowPanel;

            //Set reference to this class on the first WindowPanel so that the close on Window Panel is in sync with the ModalDialog
            if (objChildWindow != null)
                objChildWindow.ModalDialogInstance = objModalDialog;


            //For non modal - objModalDialog.TransparentContainer.Visibility = Visibility.Collapsed;
            objModalDialog.HookOwnerEventToRestrictFocus();

            //On resize, reposition the dialog box
            //objRoot.SizeChanged += new SizeChangedEventHandler(objModalDialog.objOwner_SizeChanged);
            objModalDialog.Owner.SizeChanged += new SizeChangedEventHandler(objModalDialog.objOwner_SizeChanged);

            if (objModalDialog.Owner != objRoot)
                Application.Current.Host.Content.Resized += new EventHandler(objModalDialog.Content_Resized);

            //objModalDialog.Owner.LayoutUpdated += new EventHandler(objModalDialog.Owner_LayoutUpdated);

            if (titleBar != null)
                objModalDialog._dragDropInstance = new ModalDialogDragDrop(objModalDialog, titleBar);

            objModalDialog.Focus();
            if (controlToFocusOn != null)
                controlToFocusOn.Focus();


            return objModalDialog;
        }

        private void ModalDialog_DialogBoxClosing(object sender, DialogBoxClosingEventArgs e)
        {
            this.OnDialogBoxClosing(e); //Pass the confirmation of close
        }

        private void ModalDialog_DialogBoxClosed(object sender, DialogBoxEventArgs e)
        {
            this.Close(DialogResult.None, false); //Close without confirmation
        }

        private void ModalDialog_Dragged(object sender, RoutedEventArgs e)
        {
            if (this.Owner != null)
                this._popup.PlaceInsideOwner(this.Owner);

        }

        private void objModalDialog_Loaded(object sender, RoutedEventArgs e)
        {
            if (this.Child != null)
                this.Child.PlaceInCenter(this.Child.Parent as FrameworkElement);

            this.Loaded -= new RoutedEventHandler(this.objModalDialog_Loaded);
        
        }

        private class ModalDialogDragDrop
        {
            private ModalDialog _modalDialogInstance;
            private UIElement _titleBar;
            private Point _startingDragPoint;

            public ModalDialogDragDrop(ModalDialog modalDialogInstance, UIElement titleBar)
            { 
                _modalDialogInstance = modalDialogInstance;
                _titleBar = titleBar;

                _titleBar.MouseLeftButtonDown += new MouseButtonEventHandler(_titleBar_MouseLeftButtonDown);
            }

            public void UnRegister()
            {
                _titleBar.MouseLeftButtonDown -= new MouseButtonEventHandler(_titleBar_MouseLeftButtonDown);
            }

            void _titleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                //start Dragging
                _titleBar.CaptureMouse();

                // set the starting point for the drag
                _startingDragPoint = e.GetPosition(_titleBar);

                _titleBar.MouseMove += new MouseEventHandler(_titleBar_MouseMove);
                _titleBar.MouseLeftButtonUp += new MouseButtonEventHandler(_titleBar_MouseLeftButtonUp);


            }

            void _titleBar_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
            {
                //Stop Dragging
                _titleBar.ReleaseMouseCapture();

                _titleBar.MouseMove -= new MouseEventHandler(_titleBar_MouseMove);
                _titleBar.MouseLeftButtonUp -= new MouseButtonEventHandler(_titleBar_MouseLeftButtonUp);
            }

            void _titleBar_MouseMove(object sender, MouseEventArgs e)
            {
                Point position = e.GetPosition(_modalDialogInstance.Owner);

                //_modalDialogInstance._popup.HorizontalOffset = position.X - _startingDragPoint.X;
                //_modalDialogInstance._popup.VerticalOffset = position.Y - _startingDragPoint.Y;

                Canvas.SetLeft(_modalDialogInstance.Child, position.X - _startingDragPoint.X);
                Canvas.SetTop(_modalDialogInstance.Child, position.Y - _startingDragPoint.Y);

            }


        
        }

        private void Content_Resized(object sender, EventArgs e)
        {
            if (this.Owner != null)
                this._popup.PlaceInsideOwner(this.Owner);
        }

        //private void Owner_LayoutUpdated(object sender, EventArgs e)
        //{
        //    if (this.Owner != null)
        //        this.PlaceInsideOwner(this.Owner);
        //}

        private void objOwner_SizeChanged(object sender, SizeChangedEventArgs e)
        {

            if (this.Owner != null)
                this._popup.PlaceInsideOwner(this.Owner);

        }

        private void HookOwnerEventToRestrictFocus()
        {
            //A separate non statis method is added so that we can have a non-static event handler
            this.Owner.GotFocus += new RoutedEventHandler(owner_GotFocus);

        }

        void owner_GotFocus(object sender, RoutedEventArgs e)
        {
            //As soon as any of the Element of the owner receives focus, change the focus to this Message box

            if (!this.IsFocusOnChild(this.ModalDialogRoot, e))
                this.Focus();

        }

        /// <summary>
        /// Determines whether [is focus on child] [the specified obj parent].
        /// </summary>
        /// <param name="objParent">The obj parent.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        /// <returns>
        /// 	<c>true</c> if [is focus on child] [the specified obj parent]; otherwise, <c>false</c>.
        /// </returns>
        private bool IsFocusOnChild(Panel objParent, RoutedEventArgs e)
        {
            bool blnResult;
            foreach (var currentElement in objParent.Children)
            {
                if (currentElement == e.OriginalSource)
                    return true;
                else if (currentElement is Panel)
                {
                    blnResult = this.IsFocusOnChild((Panel)currentElement, e);
                    if (blnResult)
                        return blnResult;
                }
            }

            return false;

        }

        public bool Close()
        {
            return this.Close(DialogResult.None, true);
        }

        public bool Close(DialogResult actionTaken)
        {
            return this.Close(DialogResult.None, true);
        }

        public bool Close(DialogResult actionTaken, bool blnConfirm)
        {

            if (blnConfirm)
            {
                DialogBoxClosingEventArgs e = new DialogBoxClosingEventArgs();
                e.ActionTaken = actionTaken;
                this.OnDialogBoxClosing(e);

                if (e.Cancel)
                    return false; //client has cacelled the close operation
            }

            this.Owner.GotFocus -= new RoutedEventHandler(owner_GotFocus);

            this.Owner.SizeChanged -= new SizeChangedEventHandler(this.objOwner_SizeChanged);
            Application.Current.Host.Content.Resized -= new EventHandler(this.Content_Resized);
            //this.Owner.LayoutUpdated -= new EventHandler(this.Owner_LayoutUpdated);

            //FrameworkElement objRoot = Application.Current.RootVisual as FrameworkElement;
            //if (objRoot != null)
            //    objRoot.SizeChanged -= new SizeChangedEventHandler(this.objOwner_SizeChanged);

            //((Panel)this.Owner).Children.Remove(this);

            if (this._dragDropInstance != null)
                this._dragDropInstance.UnRegister();

            this._popup.IsOpen = false;

            if (this._originalOwner != null && this._originalOwner is WindowPanel)
            {
                ((WindowPanel)this._originalOwner).Dragged -= new RoutedEventHandler(this.ModalDialog_Dragged);
                ((WindowPanel)this._originalOwner).DialogBoxClosing -= new DialogBoxClosingEventHandler(this.ModalDialog_DialogBoxClosing);
                ((WindowPanel)this._originalOwner).DialogBoxClosed -= new DialogBoxClosedEventHandler(this.ModalDialog_DialogBoxClosed);
            }

            //Utilities.GetRootPanel().Children.Remove(this._popup);
            //Utilities.GetPanelFromParents(this.Owner).Children.Remove(this._popup);

            this.ChildContainer.Children.Remove(this.Child);

            this.OnDialogBoxClosed(actionTaken);

            return true;
        }

        public static bool Close(FrameworkElement child)
        {
            return Close(child, DialogResult.None);
        }

        public static bool Close(FrameworkElement child, DialogResult actionTaken)
        {
            if (child == null || child.Visibility != Visibility.Visible)
                return false;

            ModalDialog objCurrentInstance = GetCurrentModalDialogInstance(child);
            if (objCurrentInstance != null && objCurrentInstance.Visibility == Visibility.Visible)
                return objCurrentInstance.Close(actionTaken);
            else
                return false;

        }

        //public static void CloseAllModalChildren()
        //{
        //    CloseAllModalChildren(null, DialogResult.None);
        //}

        //public static void CloseAllModalChildren(FrameworkElement owner)
        //{
        //    CloseAllModalChildren(owner, DialogResult.None);
        //}


        //public static void CloseAllModalChildren(FrameworkElement owner, DialogResult actionTaken)
        //{

        //    if (owner == null)
        //    {
        //        owner = Application.Current.RootVisual as FrameworkElement;

        //        if (owner == null)
        //            return;
        //    }

        //    Grid objModalRoot = owner.FindName("ModalDialogRoot") as Grid;

        //    if (objModalRoot != null && objModalRoot.Parent != null && objModalRoot.Parent is ModalDialog)
        //    {
        //        ModalDialog objModal = objModalRoot.Parent as ModalDialog;
        //        objModal.Close(actionTaken);
        //    }


        //    //foreach (var currentElement in ((Panel)owner).Children)
        //    //{

        //    //    if (currentElement is ModalDialog && currentElement.Visibility == Visibility.Visible)
        //    //    {
        //    //        ((ModalDialog)currentElement).Close(actionTaken);
        //    //    }
        //    //    else if (currentElement is Panel)
        //    //    {
        //    //        CloseAllModalChildren((Panel) currentElement, actionTaken);
        //    //    }
        //    //}

        //}


        /// <summary>
        /// Called when [dialog box closed].
        /// </summary>
        /// <param name="actionTaken">The action taken.</param>
        protected virtual void OnDialogBoxClosed(DialogResult actionTaken)
        {
            DialogBoxClosedEventHandler DialogBoxClosedEvent = this.DialogBoxClosed;

            if (DialogBoxClosedEvent != null)
            {
                DialogBoxEventArgs e = new DialogBoxEventArgs();
                //e.OriginalSource = this;
                e.ActionTaken = actionTaken;
                DialogBoxClosedEvent(this, e);
            }
        }

        protected virtual void OnDialogBoxClosing(DialogBoxClosingEventArgs e)
        {
            DialogBoxClosingEventHandler DialogBoxClosingEvent = this.DialogBoxClosing;

            if (DialogBoxClosingEvent != null)
            {
                //e.OriginalSource = this;
                e.Cancel = false;
                DialogBoxClosingEvent(this, e);
            }
        }


    }//End of class

    public static partial class Extensions
    {
        public static ModalDialog ShowDialog(this FrameworkElement child)
        {
            return ModalDialog.Show(null, child, null, null);
        }

        public static ModalDialog ShowDialog(this FrameworkElement child, FrameworkElement owner)
        {
            return ModalDialog.Show(owner, child, null, null);
        }

        public static ModalDialog ShowDialog(this FrameworkElement child, Control controlToFocusOn)
        {
            return ModalDialog.Show(null, child, controlToFocusOn, null);
        }

        public static ModalDialog ShowDialog(this FrameworkElement child, FrameworkElement owner, Control controlToFocusOn)
        {
            return ModalDialog.Show(owner, child, controlToFocusOn, null);
        }

        public static ModalDialog ShowDialog(this FrameworkElement child, FrameworkElement owner, Control controlToFocusOn, UIElement titleBar)
        {
            return ModalDialog.Show(owner, child, controlToFocusOn, titleBar);
        }

        public static bool CloseDialog(this FrameworkElement child)
        {
            return ModalDialog.Close(child);
        }

        public static bool CloseDialog(this FrameworkElement child, DialogResult actionTaken)
        {
            return ModalDialog.Close(child, actionTaken);
        }

        //public static void CloseAllModalChildren(this Panel owner)
        //{
        //    ModalDialog.CloseAllModalChildren(owner, DialogResult.None);
        //}

        //public static void CloseAllModalChildren(this Panel owner, DialogResult actionTaken)
        //{
        //    ModalDialog.CloseAllModalChildren(owner, actionTaken);
        //}


    }

}
